# V交流：18223205366
# 三要素转债收益回测
# -*- coding:utf-8 -*-
"""
代码思路：
1、获得每周交易日最后一天的数据
2、取到数据的前20条
3、取出数据的排名、价格
4、记录第一次的总投入资金K，以及最后一次的总计资金F
5、用上期在而本期不在的转债价格-本期在而上期不在的转债价格，得出本期投入资金W
6、记录出资金数组：[-k,W1,W2,W3,W4……,F]
7、记录出日期数组：[2021-06-18,2021-06-25,2021-07-02,2021-07-09,……]
8、使用XIRR函数计算年化收益率
"""

import json
import re
from datetime import date

import pandas as pd
from pyxirr import xirr

from Config import global_config
from util.DateUtils import parse_ymd
from util.FileUtils import read_file


def data_back(num):
    """
    数据回测主函数
    :return:
    """
    allDataList = []
    timeList = []
    crontab_file_path = global_config.get('config', 'crontab_file_path')
    str = read_file(crontab_file_path)
    # print(str)
    pattern = re.compile(r'(\d{4}-\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2}:\d{1,2})')
    lines = str.splitlines()
    for i, line in enumerate(lines):
        search = re.search(pattern, line)
        if search:
            # 1、6代表取每个周日的数据，该数据和周五收盘的数据相同，同时也和公众号推送的文章对应
            if parse_ymd(search.group()).weekday() == 6:
                # print(lines[i][0:10])
                timeList.append(parse_ymd(lines[i]))
                dataArr = lines[i + 1].replace("'", "\"")
                # print(dataArr)
                jsonArr = json.loads(dataArr)
                # print(jsonArr)
                dataList = []
                # 2、取到数据的前num条，如果不足num条就取出全部
                for n in range(min(num, len(jsonArr))):
                    simpleData = []
                    arr = jsonArr[n]
                    # 3、取出数据的排名、价格
                    rank = arr[0]
                    price = arr[7]
                    code = arr[2]
                    name = arr[3]
                    simpleData.append(rank)
                    simpleData.append(price)
                    simpleData.append(code)
                    simpleData.append(name)
                    dataList.append(simpleData)
                allDataList.append(dataList)
    # print(allDataList)
    # 7、记录出日期数组：[2021-06-18,2021-06-25,2021-07-02,2021-07-09,2021-07-16,2021-07-23,2021-07-30,2021-08-06]
    # print([time.strftime("%Y-%m-%d") for time in timeList])
    handled_data_list = handle_data_list(allDataList)
    # print(handled_data_list)
    # 8、使用XIRR函数计算年化收益率
    xirr_data = '%.2f%%' % (xirr(timeList, handled_data_list) * 100)
    # print(xirr_data)
    return xirr_data


def handle_data_list(dataList):
    """
    处理数据，最终返回资金数组
    :param dataList:
    :return:
    """
    finalDataList = []
    initPrice = 0
    finalPrice = 0
    weekPriceList = []
    # 4、记录第一次的总投入资金K，以及最后一次的总计资金F
    for data in dataList[0]:
        initPrice += float(data[1]) * 10
    for data in dataList[len(dataList) - 1]:
        finalPrice += float(data[1]) * 10
    # 5、比较本期名单和上期名单中不同的转债，用上期在本期不在的转债-本期在上期不在的转债价格，得出本期投入资金W
    if len(dataList) > 2:
        for i in range(1, len(dataList) - 1):
            weekPrice = handle_data(dataList[i], dataList[i + 1])
            weekPriceList.append(round(weekPrice, 2))
    # 6、记录出资金数组：[-20000,-200,-300,-400……,38000]，即第一期投入金额和每期的投入资金[-k,W1,W2,W3,W4……,F]
    finalDataList.append(-round(initPrice, 2))
    finalDataList += weekPriceList
    finalDataList.append(round(finalPrice, 2))
    return finalDataList


def handle_data(arr1, arr2):
    """
    比较本期名单和上期名单中不同的转债，用上期在本期不在的转债-本期在上期不在的转债价格，得出本期投入资金W
    :param arr1:
    :param arr2:
    :return:
    """
    sumPrice = 0
    dict1 = {}
    dict2 = {}
    codeArr1 = []
    codeArr2 = []
    for arr in arr1:
        dict1[arr[2]] = arr[1]
        codeArr1.append(arr[2])
    for arr in arr2:
        dict2[arr[2]] = arr[1]
        codeArr2.append(arr[2])
    # print(dict1)
    # print(dict2)
    diffArr1 = diff_arr(codeArr2, codeArr1)
    for code in diffArr1:
        sumPrice += float(dict1[code]) * 10
    diffArr2 = diff_arr(codeArr1, codeArr2)
    for code in diffArr2:
        sumPrice -= float(dict2[code]) * 10
    return sumPrice


def diff_arr(listA, listB):
    """
    求差集，在B中但不在A中
    :param listA:
    :param listB:
    :return:
    """
    retE = [i for i in listB if i not in listA]
    # print("retE is: ", retE)
    return retE


def xirr_calc():
    """
    xirr函数测试
    :return:
    """
    dates = [date(2020, 1, 1), date(2021, 1, 1), date(2022, 1, 1)]
    amounts = [-1000, 1000, 1000]

    # feed columnar data
    print(xirr(dates, amounts))
    # feed tuples
    print(xirr(zip(dates, amounts)))
    # feed DataFrame
    print(xirr(pd.DataFrame({"dates": dates, "amounts": amounts})))


if __name__ == '__main__':
    for i in range(1, 21):
        back = data_back(i)
        print(i, back)
        # xirr_calc()
